﻿using SoundEngine3.AudioProcessing;
using SoundEngine3.DspPlugins;
using SoundEngine3.DspPlugins.Meta;
using SoundEngine3.MIDI.Meta;
using System;
using System.Collections.Generic;
using ZquenceStudio3.Core;
using ZquenceStudio3.Core.DspPlugins;
using ZquenceStudio3.DspPlugins;

namespace ZquenceStudio3Host.DspPlugins.Synthesizers
{
    public class MidiTerminalDescription : IDspPlugin
    {
        public DspPluginInfo GetDspPluginInfo()
        {
            return new DspPluginInfo("MidiTerminal", DspType.Synthesizer);
        }

        public BaseDspPluginInstance CreateDsp(ZquenceStudio3Context context, DspPluginInfo info)
        {
            return new MidiTerminal(context, info);
        }
    }

    class MidiTerminal : CoreDspSynthesizerPlugin
    {
        private double mPort;
        private double mChannel;

        public int Port
        {
            get { return (int)mPort; }
            set { mPort = value; }
        }

        public byte Channel
        {
            get { return (byte)mChannel; }
            set { mChannel = value; }
        }

        public MidiTerminal(ZquenceStudio3Context application, DspPluginInfo dspPlugin)
            : base(application, dspPlugin)
        {
            SupportAudioProcessing = false;

            // Port.
            ParameterPropertiesDirect port = new ParameterPropertiesDirect(this);
            port.Label = "Port";
            port.MinValue = 0;
            port.MaxValue = 32;
            port.DirectGet += delegate () { return mPort; };
            port.DirectSet += delegate (double value) { mPort = value; };
            port.OnValueChanged += delegate (ParameterProperties parameter) { parameter.Display = Port.ToString(); };
            AddParameter(port);

            // Channel.
            ParameterPropertiesDirect channel = new ParameterPropertiesDirect(this);
            channel.Label = "Channel";
            channel.MinValue = 0;
            channel.MaxValue = 127;
            channel.DirectGet += delegate () { return mChannel; };
            channel.DirectSet += delegate (double value) { mChannel = value; };
            channel.OnValueChanged += delegate (ParameterProperties parameter) { parameter.Display = Channel.ToString(); };
            AddParameter(channel);
        }
        
        public override string PluginInfo
        {
            get { return DspPluginInfo.DefaultPluginInfo; }
        }

        public override Version Version
        {
            get { return DspPluginInfo.DefaultVersion; }
        }
        
        public override void OnProcess(BaseAudioBuffer output)
        {
            throw new NotImplementedException();
        }

        private List<MidiMessage> mMidiMessages = new List<MidiMessage>(32);

        protected override void OnProcessEvents(List<MidiMessage> midiMessages)
        {
            mMidiMessages.AddRange(midiMessages);
        }

        public override void ProcessOutputEvents(List<MidiMessage> outputEvents, out int port)
        {
            port = Port;
            int length = mMidiMessages.Count;
            if (length > 0)
            {
                for (int i = 0; i < length; i++)
                {
                    var item = mMidiMessages[i];
                    item.MidiData.Channel = Channel;

                    outputEvents.Add(item);
                }
                mMidiMessages.Clear();
            }
        }
    }
}
